package com.excilys.capicsoubank.entities;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.apache.commons.lang3.ObjectUtils;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;

/**
 * POJO Transaction.
 * 
 * @author Sébastien Bihan
 */
@Entity
@Table(name = "TRANSACTION")
public class Transaction implements Serializable {

	private static final long serialVersionUID = 1L;

	private Integer transactionId;

	private Account account;

	private DateTime date;

	private DateTime creationDate;

	private String label;

	private long amount;

	private TransactionType transactionType;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "transaction_id", unique = true, nullable = false)
	public Integer getTransactionId() {
		return transactionId;
	}

	public void setTransactionId(Integer transactionId) {
		this.transactionId = transactionId;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "account_id", nullable = false)
	public Account getAccount() {
		return account;
	}

	public void setAccount(Account account) {
		this.account = account;
	}

	@Column(name = "date")
	@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
	public DateTime getDate() {
		return date;
	}

	public void setDate(DateTime date) {
		this.date = date;
	}

	@Column(name = "creationDate")
	@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
	public DateTime getCreationDate() {
		return creationDate;
	}

	public void setCreationDate(DateTime creationDate) {
		this.creationDate = creationDate;
	}

	@Column(name = "label")
	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	@Column(name = "amount")
	public long getAmount() {
		return amount;
	}

	public void setAmount(long amount) {
		this.amount = amount;
	}

	@Enumerated(EnumType.STRING)
	@Column(name = "type")
	public TransactionType getTransactionType() {
		return transactionType;
	}

	public void setTransactionType(TransactionType transactionType) {
		this.transactionType = transactionType;
	}

	@Override
	public String toString() {
		return "Transaction [transactionId=" + transactionId + ", date=" + date
				+ ", label=" + label + ", amount=" + amount
				+ ", transactionType=" + transactionType + "]";
	}

	@Override
	public int hashCode() {
		return transactionId;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;

		if (obj == null)
			return false;

		if (getClass() != obj.getClass())
			return false;

		Transaction transaction = (Transaction) obj;

		return ObjectUtils
				.equals(transactionId, transaction.getTransactionId());
	}

	/**
	 * Builder de la classe Transaction.
	 * 
	 * @author "Grégory Coutant"
	 * 
	 */
	public static class Builder {

		private final Transaction transaction = new Transaction();

		/**
		 * Builder de l'attribut account.
		 * 
		 * @param account
		 *            Le compte
		 * @return Le builder
		 */
		public Builder account(Account account) {
			transaction.account = account;
			return this;
		}

		/**
		 * Builder de l'attribut date.
		 * 
		 * @param date
		 *            La date
		 * @return Le builder
		 */
		public Builder date(DateTime date) {
			transaction.date = date;
			return this;
		}

		/**
		 * Builder de l'attribut label.
		 * 
		 * @param label
		 *            Le label
		 * @return Le builder
		 */
		public Builder label(String label) {
			transaction.label = label;
			return this;
		}

		/**
		 * Builder de l'attribut transactionType.
		 * 
		 * @param transactionType
		 *            Le type de la transaction
		 * @return Le builder
		 */
		public Builder transactionType(TransactionType transactionType) {
			transaction.transactionType = transactionType;
			return this;
		}

		/**
		 * Builder de l'attribut amount.
		 * 
		 * @param amount
		 *            Le montant
		 * @return Le builder
		 */
		public Builder amount(long amount) {
			transaction.amount = amount;
			return this;
		}

		/**
		 * Construit la transaction.
		 * 
		 * @return La transaction
		 */
		public Transaction build() {
			return transaction;

		}
	}
}
